package lol.clann.bukkit.pluginboot.util;

import lol.clann.clannboot.annotation.inject.Inject;
import lol.clann.clannboot.annotation.svc.PostInstance;
import lol.clann.clannboot.annotation.svc.Service;
import lol.clann.clannboot.util.clazz.FieldFilter;
import lol.clann.clannboot.util.clazz.MethodFilter;
import lol.clann.clannboot.util.clazz.WrapField;
import lol.clann.clannboot.util.clazz.WrapMethod;
import org.nutz.lang.Lang;

import java.util.List;
import java.util.StringJoiner;
import java.util.stream.Collectors;

/**
 * @author pyz
 * @date 2018/8/7 下午10:02
 */
@Service(priority = Integer.MAX_VALUE)
public class NBTListUtils {

    private WrapField tagList;
    private WrapMethod appendTag;

    @Inject
    private NBTUtils nbtUtils;

    @PostInstance
    private void init() {
        tagList = NBTUtils.classNBTTagList.getField(FieldFilter.build().type(List.class));
        appendTag = NBTUtils.classNBTTagList.getMethod(MethodFilter.build().returnType(void.class, boolean.class).parameterType(NBTUtils.classNBTBase));
    }

    public void appendTag(Object nbtList, Object nbtBase) {
        appendTag.invoke(nbtList, nbtBase);
    }

    public Object getCompoundTagAt(Object nbtList, int index) {
        Object value = getValue(nbtList, index);
        return nbtUtils.getValue(value);
    }

    public double getDoubleAt(Object nbtList, int index) {
        Object value = getValue(nbtList, index);
        return (Double) nbtUtils.getValue(value);
    }

    public float getFloatAt(Object nbtList, int index) {
        Object value = getValue(nbtList, index);
        return (Float) nbtUtils.getValue(value);
    }

    public int[] getIntArrayAt(Object nbtList, int index) {
        Object value = getValue(nbtList, index);
        return (int[]) nbtUtils.getValue(value);
    }

    public String getStringTagAt(Object nbtList, int index) {
        Object value = getValue(nbtList, index);
        return (String) nbtUtils.getValue(value);
    }

    public List getValue(Object handle) {
        return (List) tagList.get(handle);
    }

    public Object getValue(Object handle, int index) {
        List list = getValue(handle);
        return list.get(index);
    }

    public Object removeTag(Object nbtList, int index) {
        List list = (List) nbtUtils.getValue(nbtList);
        return list.remove(index);
    }

    public void setTag(Object nbtList, int index, Object nbtBase) {
        getValue(nbtList).set(index, nbtBase);
    }

    public int size(Object nbtList) {
        List tagList = getValue(nbtList);
        return tagList == null ? 0 : tagList.size();
    }

    public List<String> getStringValue(Object tagList) {
        List<Object> list = (List<Object>) nbtUtils.getValue(tagList);
        return list.stream()
                .map(o -> (String) nbtUtils.getValue(o))
                .collect(Collectors.toList());
    }

    /**
     * List<NBTTagCompound>
     *
     * @param tagList
     * @return
     */
    public List<Object> getCompoundValue(Object tagList) {
        List<Object> list = (List<Object>) nbtUtils.getValue(tagList);
        return list;
    }

    public String getNBTFormatJson(Object list) {
        StringJoiner sj = new StringJoiner(",", "[", "]");
        List<Object> tagList = (List<Object>) nbtUtils.getValue(list);
        int n = 0;
        for (Object nbtBase : tagList) {
            sj.add(n + ":" + nbtUtils.getNBTFormatJson(nbtBase));
            n++;
        }
        return sj.toString();
    }

    public int getSize(Object tagList) {
        List list = (List) nbtUtils.getValue(tagList);
        return list == null ? 0 : list.size();
    }

    public Object newList() {
        try {
            return NBTUtils.classNBTTagList.getHandle().newInstance();
        } catch (Exception e) {
            throw Lang.wrapThrow(e);
        }
    }
}
